package com.ruifu.doc.service.impl;

import com.fhzncloud.cloud.common.security.service.CloudUser;
import com.github.tobato.fastdfs.domain.StorePath;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import com.ruifu.common.eneity.ConversionTaskQueue;
import com.ruifu.common.po.DmFile;
import com.ruifu.doc.conf.DirectConfig;
import com.ruifu.doc.conf.FileConfig;
import com.ruifu.doc.mapper.DmDocVerMapper;
import com.ruifu.doc.mapper.DmFileMapper;
import com.ruifu.doc.service.DmFileService;
import com.ruifu.doc.utils.FastDFSClient;
import com.ruifu.doc.utils.GetPreviewFileTypeUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Date;
import java.util.List;

/**
 * 文件业务逻辑层
 *
 * @author nyr
 */
@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class DmFileServiceImpl implements DmFileService {

    /**
     * 文件操作配置类
     */
    @Autowired
    private FileConfig fileConfig;

    /**
     * 文件Dao对象
     */
    @Autowired(required = false)
    private DmFileMapper dmFileMapper;

    /**
     * 文件版本Dao对象
     */
    @Autowired(required = false)
    private DmDocVerMapper dmDocVerMapper;

    @Autowired
    private FastDFSClient fastDFSClient;

    @Autowired
    private FastFileStorageClient storageClient;

    @Autowired
    GetPreviewFileTypeUtils getPreviewFileTypeUtils;
    /**
     * rabbitMq操作类
     */
    @Autowired
    private AmqpTemplate rabbitTemplate;

    /**
     * 文件上传进入队列返回文件id
     * @param file 文件对象
     * @param cloudUser
     * @return
     * @throws IOException
     */
    @Override
    public Long uploadFile(MultipartFile file, CloudUser cloudUser) throws IOException {
        //获取文件后缀
        String extName = FilenameUtils.getExtension(file.getOriginalFilename());

        //上传文件获取存储路径
        StorePath storePath = fastDFSClient.uploadFile(file);

        /*创建文件对象，存储文件信息*/
        DmFile dmFile = new DmFile();

        //文件名
        dmFile.setFiFileName(file.getOriginalFilename());

        //是否被压缩
        dmFile.setFiIsCompresSed(fileConfig.getCompressedList().contains(extName));

        //文件大小
        dmFile.setFiFileSize((int) file.getSize());

        //所在数据仓ID号
        dmFile.setFiVaultId(storePath.getGroup());

        //存储方式
        dmFile.setFiStorType(3);

        //存储路径/
        dmFile.setFiStorPath(storePath.getFullPath());

        dmFileMapper.insert(dmFile, cloudUser);

        /*判断该文件是否需要发送转换消息队列,并且不是压缩文件*/
        if (!dmFile.getFiIsCompresSed() && !fileConfig.getPreviewType().contains(extName)) {

            /*包装task：file，转换类型，原文件id*/
            //创建转换文件队列实体
            ConversionTaskQueue conversionTaskQueue = new ConversionTaskQueue();

            //从数据库获取完整的文件信息
            DmFile newDmFile = dmFileMapper.findById(dmFile.getFiFileId());

            //设置文件信息对象
            conversionTaskQueue.setDmFile(newDmFile);

            //设置要转换的类型
            String previewFileType = getPreviewFileTypeUtils.getPreviewFileType(extName, fileConfig.getConversionMap());

            //判断是否存在该文件要转换的类型
            if (previewFileType != null) {

                //设置转换后的文件类型
                conversionTaskQueue.setType(previewFileType);

                //发送message到RabbitMQ
                rabbitTemplate.convertAndSend(DirectConfig.QUEUE, conversionTaskQueue);
            }

        }
        return dmFile.getFiFileId();
    }

    /**
     * 文件上传返回文件id
     * @param file
     * @param cloudUser
     * @return
     * @throws IOException
     */
    @Override
    public Long upload(MultipartFile file, CloudUser cloudUser) throws IOException {
        //上传文件获取存储路径
        StorePath storePath = fastDFSClient.uploadFile(file);
        DmFile dmFile = new DmFile();
        //文件名
        dmFile.setFiFileName(file.getOriginalFilename());
        //根据文件后缀判断是否被压缩
        dmFile.setFiIsCompresSed(fileConfig.getCompressedList().contains(FilenameUtils.getExtension(file.getOriginalFilename())));
        //文件大小
        dmFile.setFiFileSize((int) file.getSize());
        //所在数据仓ID号
        dmFile.setFiVaultId(storePath.getGroup());
        //存储方式
        dmFile.setFiStorType(3);
        //存储路径/
        dmFile.setFiStorPath(storePath.getFullPath());
        dmFileMapper.insert(dmFile, cloudUser);
        return dmFile.getFiFileId();
    }

    /**
     * 单个文件下载
     * @param fiFileId 文件id
     * @param response
     * @param cloudUser
     * @throws Exception
     */
    @Override
    public void downloadFile(Long fiFileId, HttpServletResponse response, CloudUser cloudUser) throws Exception {
        DmFile dmFile = dmFileMapper.findById(fiFileId);
        //截取存储路径获得文件标识
        String fileId = dmFile.getFiStorPath();
        //获取文件名称
        String fiFileName = dmFile.getFiFileName();
        //设置响应类型
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fiFileName, "UTF-8"));
        //应用程序强制下载
        response.setContentType("application/force-download");
        //下载
        fastDFSClient.downloadFile(fileId, response);
        //最后下载人
        dmFile.setFiLastRead(cloudUser.getId());
        //最后下载时间
        dmFile.setFiLastReadDate(new Date());
        dmFileMapper.update(dmFile);
    }

    /**
     * 文件删除
     * @param fiFileId 文件Id
     * @param cloudUser
     * @throws Exception
     */
    @Override
    public void deleteFile(Long fiFileId, CloudUser cloudUser) throws Exception {
        //根据文件Id获取文件信息对象
        DmFile dmFile = dmFileMapper.findById(fiFileId);
        //截取存储路径获得文件标识
        String fileId = dmFile.getFiStorPath().substring(dmFile.getFiStorPath().indexOf("g"));
        log.info("文件路径：{}",fileId);
        try {
            //文件删除
            fastDFSClient.deleteFile(fileId);
        } catch (Exception e) {
            e.printStackTrace();
            log.error(dmFile.getFiFileName()+ "在文件服务器中不存在,删除失败");
        }finally {
            //最后修改人
            dmFile.setFiLastUpdator(cloudUser.getId());
            //最后修改时间
            dmFile.setFiLastUpdate(new Date());
            //删除标记
            dmFile.setFiDelFlag(true);
            //更新修改的信息
            dmFileMapper.update(dmFile);

            //查询该文件的关联文件并删除
            List<DmFile> dmFileList = dmFileMapper.findByPFileIdAndStrType(dmFile.getFiFileId(), null, cloudUser);
            //判断不为空,遍历删除
            if (dmFileList != null && dmFileList.size() != 0) {
                //遍历子文件列表
                for (DmFile file : dmFileList) {
                    //调用删除文件的方法
                    this.deleteFile(file.getFiFileId(), cloudUser);
                }
            }
        }
    }

    /**
     * 文件替换
     * @param fiFileId 原文件信息ID
     * @param file 新文件
     * @param cloudUser
     * @throws Exception
     */
    @Override
    public void changeFile(Long fiFileId, MultipartFile file, CloudUser cloudUser) throws Exception {
        //删除原文件信息及文件
        this.deleteFile(fiFileId, cloudUser);
        //上传新文件,获得新文件信息的id
        Long newFiFileId = this.uploadFile(file, cloudUser);
        //修改文档版本表中数据库外键字段
        dmDocVerMapper.updateByDvFileId(fiFileId, newFiFileId, cloudUser);
    }

    /**
     * copy文件
     * @param fiFileId 文件id
     * @param cloudUser
     * @return
     * @throws Exception
     */
    @Override
    public Long copyFile(Long fiFileId, CloudUser cloudUser) throws Exception {
        //根据文件id获取文件信息
        DmFile dmFile = dmFileMapper.findById(fiFileId);

        //获取文件标识
        String fileId = dmFile.getFiStorPath();

        //获取文件后缀
        String extName = FilenameUtils.getExtension(dmFile.getFiFileName());

        //从fastDFS中获取文件的byte数组
        byte[] bytes = fastDFSClient.copyFile(fileId);

        //将数组转换为流对象并上传
        StorePath storePath = storageClient.uploadFile(new ByteArrayInputStream(bytes), dmFile.getFiFileSize(), extName, null);

        /*修改文件信息*/
        //存储路径/
        dmFile.setFiStorPath(storePath.getFullPath());

        //所在数据仓ID号
        dmFile.setFiVaultId(storePath.getGroup());

        /*将id清空,并新建到数据库中*/
        dmFile.setFiFileId(null);

        dmFileMapper.insert(dmFile, cloudUser);

        return dmFile.getFiFileId();
    }

    /**
     * 批量下载
     * @param fiFileIds 文件id数组
     * @param response 响应体
     * @param cloudUser
     * @throws Exception
     */
    @Override
    public void downloadPLFile(Long[] fiFileIds, HttpServletResponse response, CloudUser cloudUser) throws Exception {
        //遍历文件id数组
        for (Long fiFileId : fiFileIds) {
            //调用单个文件下载
            this.downloadFile(fiFileId, response, cloudUser);
        }
    }

    /**
     * 预览文件
     *
     * @param fiFileId  文件id
     * @param cloudUser 用户对象
     * @return 文件访问路径
     */
    @Override
    public String previewFile(Long fiFileId, CloudUser cloudUser) {
        /*根据id查询源文件信息*/
        DmFile dmFile = dmFileMapper.findById(fiFileId);

        //获取文件后缀
        String extName = FilenameUtils.getExtension(dmFile.getFiFileName());

        //判断该文件是否本身就是预览文件 源文件为PDF等
        if (fileConfig.getPreviewType().contains(extName)) {
            //返回当前源文件的完整访问路径
            return fastDFSClient.getResAccessUrl(dmFile.getFiStorPath());
        }
        /*判断该文件的预览文件类型*/
        String previewFileType = this.getPreviewFileTypeUtils.getPreviewFileType(extName, fileConfig.getConversionMap());

        //判断预览文件类型是否存在
        if (previewFileType == null) {
            return ("该文件不支持预览,请下载文件后查阅");
        }
        //根据预览文件类型获取对应的数值
        Integer fiStrType = fileConfig.getTypeNumMap().get(previewFileType);

        /*根据父文件id和关联文件类型查询预览文件*/
        //根据要预览的文件类型和源文件Id查询关联文件
        List<DmFile> dmFileList = dmFileMapper.findByPFileIdAndStrType(dmFile.getFiFileId(), fiStrType, cloudUser);

        if (dmFileList == null || dmFileList.size() == 0) {
            return ("该文件的预览文件不存在,请联系系统管理员");
        }

        //获取关联文件集合中第一个元素，即预览文件
        DmFile previewFile = dmFileList.get(0);

        //返回预览文件的完整访问路径
        return fastDFSClient.getResAccessUrl(previewFile.getFiStorPath());
    }


}
